package com.mrd.frame.onlinepay.refund.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.TradeStatus;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.mrd.frame.domain.AccessConfig;
import com.mrd.frame.domain.Order;
import com.mrd.frame.domain.OrderInteraction;
import com.mrd.frame.domain.TradeStatement;
import com.mrd.frame.domain.message.RefundMessage;
import com.mrd.frame.domain.params.RefundParams;
import com.mrd.frame.onlinepay.AliPayApi;
import com.mrd.frame.onlinepay.AliPayApi.AliCodeEnu;
import com.mrd.frame.onlinepay.refund.IRefund;
import com.mrd.frame.service.OrderInteractionService;
import com.mrd.frame.service.OrderService;
import com.mrd.frame.service.TradeStatementService;
import com.mrd.weixinpay.util.Constents;
import com.mrd.weixinpay.util.PayCommonUtil;

/**
 * 支付宝退款请求
 * @author han
 */
@Component("aliRefund")
public class AliRefund extends AliPayApi implements IRefund {
	private static final Logger log = Logger.getLogger(AliRefund.class);
	
	/**
	 * 退款实现类
	 * @author han
	 */
	@Override
	public Map<String, Object> refund(HttpServletResponse response,
			OrderInteraction orderInt,
			OrderInteractionService orderInteractionService,
			AccessConfig accessConfig, Order order, TradeStatement payStatement,
			RefundParams refParams, OrderService orderService,
			TradeStatementService tradeStatementService) {

		Map<String, Object> reMap = new HashMap<String, Object>();//返回
		SortedMap<Object, Object> xmlMap = new TreeMap<Object, Object>();//参数
		String resultMsg = "";
		RefundMessage refundMsg = new RefundMessage();

		//转换出一个要保存参数map，保存到交互记录的xml或者用于交易
		xmlMap = getPayOrderXmlMap(order, refParams);
		
		// 向第三方的支付请求存入交互记录表中
		try{
			saveOrderInteraction( order, orderInt,orderInteractionService);
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		//服务端向第三方发起退款请求信息存到交互表中
		try{
			recordSendOrderInteraction( orderInt,orderInteractionService, xmlMap);
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		try{
			// 发起支付
			AlipayTradeRefundResponse result = sendRefund(xmlMap,accessConfig);

			// 将支付宝支付返回的信息存入交互表中
			SaveRtnMsg(result, orderInt , orderInteractionService,
					  order, payStatement, refundMsg , refParams,  orderService, tradeStatementService);	
			
		}catch(Exception ex){
			// 服务端向第三方发起退款请求信息存到交互表中
			orderInt.setCreateTime(new Date());
			orderInt.setParameters(PayCommonUtil.getRequestXml(xmlMap));
			orderInt.setOrderInteractionId(String.valueOf(System.currentTimeMillis()));
			orderInt.setType("B2");
			orderInt.setStatus("1");
			Integer B2 = orderInteractionService.insert(orderInt);

			// 封装返回给客户端的信息
			// RefundMessage refundMsg = new RefundMessage();
			refundMsg.setOutRefundNo(refParams.getOutRefundNo());// 商户退款单号
			refundMsg.setOutTradeNo(refParams.getOutTradeNo());// 商户订单号
			refundMsg.setCode(Integer.parseInt("0"));// 请求失败
			refundMsg.setFundChange("N");// 资金未发生变化
			refundMsg.setMessage(Constents.FAULTMESSAGE);// 请求信息反馈
			refundMsg.setOrderId(payStatement.getOrderId());// 平台支付单号
			refundMsg.setResultCode("FAIL");// 返回代码
			refundMsg.setReturnCode("FAIL");// 返回代码
			refundMsg.setReturnMsg("退款失败,请稍后重新发起退款请求");// 第三方返回错误提示信息
			refundMsg.setSign(refParams.getSign());// 签名
			refundMsg.setTotalAmount(refParams.getTotalAmount());// 订单总金额
		}
		
		reMap.put("resultMsg", refundMsg);
		return reMap;
	}

	/**
	 * 保存订单交互记录
	 * @author han
	 * @param order
	 * @param orderInt
	 * @param type 记录步骤标识
	 * @param status 发起状态
	 * @param orderInteractionService
	 */
	private void saveOrderInteraction(Order order,OrderInteraction orderInt,
			OrderInteractionService orderInteractionService) throws Exception{
		// 将客户端向服务端发起的退款请求存入交互表中
		orderInt.setOrderId(order.getOrderId());
		orderInt.setType("B1");
		orderInt.setStatus("0");
		int b1 = orderInteractionService.insert(orderInt);
	}
	
	/**
	 * 服务端向第三方发起退款请求信息存到交互表中
	 * @param order
	 * @param orderInt
	 * @param orderInteractionService
	 * @throws Exception
	 */
	private void recordSendOrderInteraction(OrderInteraction orderInt,
			OrderInteractionService orderInteractionService,SortedMap<Object, Object> packageParams) throws Exception{
		orderInt.setCreateTime(new Date());
		orderInt.setParameters(PayCommonUtil.getRequestXml(packageParams));
		orderInt.setOrderInteractionId(String.valueOf(System.currentTimeMillis()));
		orderInt.setType("B2");
		orderInt.setStatus("0");
		int b1 = orderInteractionService.insert(orderInt);
	}
	
	/**
	 * 封装一个保存参数以及支付参数的Map
	 * 将map保存到记录表，同时用于支付
	 * @author han
	 * @return SortedMap<Object, Object> 
	 */
	public SortedMap<Object, Object> getPayOrderXmlMap(Order order, RefundParams refParams){
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("outTradeNo", order.getOrderId());//订单号
		packageParams.put("outRequestNo", "");//多次推款号
		packageParams.put("refundAmount", refParams.getRefundAmount());//退款金额
		packageParams.put("storeId", "test_store_id");//商户门店编号
		packageParams.put("refundReason", refParams.getRefundReason());//退款原因
		packageParams.put("sign", refParams.getSign());//签名，支付宝没使用到
		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		log.info("支付宝支付请求发送的消息：" + requestXML);
		System.out.println("支付宝支付请求发送的消息：" + requestXML);
		return packageParams;
	}
	
	/**
	 * 发起退款申请
	 * @author han
	 * @param packageParams SortedMap<Object, Object>
	 * @return AlipayF2FRefundResult
	 */
	private AlipayTradeRefundResponse sendRefund(SortedMap<Object, Object> packageParams,AccessConfig accessConfig) throws Exception{
		int total = Integer.parseInt((String)packageParams.get("refundAmount"));
		float val  = (float)total/100;
		AlipayTradeRefundModel model = new AlipayTradeRefundModel();
		model.setOutTradeNo((String)packageParams.get("outTradeNo"));
//		model.setTradeNo((String)packageParams.get("outRequestNo"));
		model.setOutRequestNo((String)packageParams.get("outRequestNo"));
		model.setRefundAmount(String.valueOf(val));
		model.setRefundReason((String)packageParams.get("refundReason"));
		AlipayTradeRefundResponse refundResponse = tradeRefundToResponse(model,accessConfig.getUserKey());
		return refundResponse;
	}
	
	/**
	 * 保存退款返回信息
	 * @author han
	 * @param result
	 * @param orderInt
	 * @param orderInteractionService
	 * @param order
	 * @param refundMsg
	 * @param refParams
	 * @param orderService
	 * @param tradeStatementService
	 */
	private void SaveRtnMsg(AlipayTradeRefundResponse response,OrderInteraction orderInt,
			OrderInteractionService orderInteractionService,
			 Order order,TradeStatement payStatement, RefundMessage refundMsg,
			RefundParams refParams, OrderService orderService,
			TradeStatementService tradeStatementService){
		
		String code = response.getCode();
		String msg = response.getMsg();
		String subCode = response.getSubCode();
		String subMsg = response.getSubMsg();
		
		int refund_fee = refParams.getRefundAmount();// 退款金额
		int total_fee = refParams.getTotalAmount();
		
		SortedMap<Object, Object> resultParams = new TreeMap<Object, Object>();
//		AlipayTradeRefundResponse response = result.getResponse();
		//返回信息
		resultParams.put("body", response.getBody());
		resultParams.put("code", response.getCode());//网关返回码
		resultParams.put("msg", response.getMsg());//网关返回码描述
		resultParams.put("outTradeNo", response.getOutTradeNo());//商户订单号 
		resultParams.put("subCode", response.getSubCode());// 业务返回码 
		resultParams.put("subMsg", response.getSubMsg());//业务返回码描述
		resultParams.put("fundChange", response.getFundChange());//本次退款是否发生了资金变化 
		resultParams.put("gmtRefundPay", response.getGmtRefundPay());//退款支付时间 
		resultParams.put("refundFee", Integer.parseInt(response.getRefundFee())*100);//总退款金额
		resultParams.put("sendBackFee", Integer.parseInt(response.getSendBackFee())*100);//实际退款金额 
		resultParams.put("storeName", response.getStoreName());//交易在支付时候的门店名称 
		resultParams.put("tradeNo", response.getTradeNo());//支付宝交易号
		orderInt.setParameters(PayCommonUtil.getRequestXml(resultParams));
		
		String resXml = PayCommonUtil.getRequestXml(resultParams);
		
		if(code.equals(AliCodeEnu.CECUSS.val())) {
			// 更新订单表
			order.setStatus("2");
			order.setThirdOrderId("");
			orderService.updateByPrimaryKeySelective(order);

			// 存入资金流水表
			TradeStatement tradeStatement = new TradeStatement();
			tradeStatement.setOrderId(order.getOrderId());
			List<TradeStatement> trade = new ArrayList<>();
			trade = tradeStatementService.selectSelective(tradeStatement);
			if(!(trade.size() > 0)) {
				tradeStatement.setOrderId(order.getOrderId());
				tradeStatement.setPayChannel("1");
				tradeStatement.setThirdOrderId("");
				tradeStatement.setTotalAmount(Integer.parseInt((String)resultParams.get("refundFee")));
				tradeStatement.setTradeNo(refParams.getOutRefundNo());
				tradeStatement.setTradeTime(new Date());
				tradeStatement.setRelatedTradeNo(refParams.getOutTradeNo());
				tradeStatement.setTradeType("2");
				tradeStatement
				        .setTradingStatementsId(String.valueOf(System.currentTimeMillis()));
				tradeStatement.setUserKey(order.getUserKey());
				tradeStatementService.insert(tradeStatement);

			}
			// 封装返回给客户端的信息
			// RefundMessage refundMsg = new RefundMessage();
			refundMsg.setOutRefundNo(refParams.getOutRefundNo());// 商户退款单号
			refundMsg.setOutTradeNo(refParams.getOutTradeNo());// 商户订单号
			refundMsg.setCashFee((String)resultParams.get("refundFee"));// 现金支付金额
			refundMsg.setCode(Integer.parseInt("1"));// 请求成功
			refundMsg.setFundChange("Y");// 资金发生变化
			refundMsg.setGmtRefundPay((String)resultParams.get("gmtRefundPay"));// 退款时间
			refundMsg.setMessage(Constents.SUCCESMESSAGE);// 请求信息反馈
			refundMsg.setOrderId(payStatement.getOrderId());// 平台支付单号
			refundMsg.setRefundAmount(Integer.parseInt((String)resultParams.get("refundFee")));// 退款的金额
			refundMsg.setRefundId(order.getOrderId());// 平台退款单号
			refundMsg.setResultCode("SUCCESS");// 返回代码
			refundMsg.setReturnCode("0");// 返回代码
			refundMsg.setReturnMsg((String)resultParams.get("subMsg"));// 返回信息
			refundMsg.setSign(refParams.getSign());// 签名
			refundMsg.setTotalAmount(total_fee);// 订单总金额
			refundMsg.setThreeRefundId("");// 第三方返回的退款单号

			// 将退款反馈至客户端的信息存入交互表
			orderInt.setCreateTime(new Date());
			orderInt.setParameters(resXml);
			orderInt.setOrderInteractionId(String.valueOf(System.currentTimeMillis()));
			orderInt.setType("B3");
			orderInt.setStatus("0");

			// 响应客户端的退款请求
			// printRefunResultToSystem(response, refundMsg, orderInt);
		} else {
			// 退款失败：更新退款订单表，返回退款结果给客户端,将此信息存入交互记录表

			// 更新退款订单为失败
			order.setStatus("0");
			orderService.updateByPrimaryKeySelective(order);

			// 封装返回给客户端的信息
			// RefundMessage refundMsg = new RefundMessage();
			refundMsg.setOutRefundNo(refParams.getOutRefundNo());// 商户退款单号
			refundMsg.setOutTradeNo(refParams.getOutTradeNo());// 商户订单号
			refundMsg.setCashFee((String)resultParams.get("refundFee"));// 现金支付金额
			refundMsg.setCode(Integer.parseInt("0"));// 请求失败
			refundMsg.setFundChange("N");// 资金未发生变化
			// refundMsg.setGmtRefundPay(new
			// SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
			// .format(new Date()));// 退款时间
			refundMsg.setMessage(Constents.FAULTMESSAGE);// 请求信息反馈
			refundMsg.setOrderId(payStatement.getOrderId());// 平台支付单号
			refundMsg.setRefundAmount(refParams.getRefundAmount());// 请求的退款的金额
			refundMsg.setRefundId(order.getOrderId());// 平台退款单号
			refundMsg.setResultCode("FAIL");// 返回代码
			refundMsg.setReturnCode("-1");// 返回代码
			refundMsg.setReturnMsg((String)resultParams.get("subMsg"));// 返回信息
			refundMsg.setSign(refParams.getSign());// 签名
			refundMsg.setTotalAmount(total_fee);// 订单总金额
			// refundMsg.setThreeRefundId(refund_id);// 第三方返回的退款单号

			// 响应客户端的退款请求
			// printRefunResultToSystem(response, refundMsg, orderInt);
		}
	}
}
